package wickethub.web.app;

import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.wicket.Page;
import org.apache.wicket.Request;
import org.apache.wicket.Response;
import org.apache.wicket.Session;
import org.apache.wicket.guice.GuiceComponentInjector;
import org.apache.wicket.protocol.http.SecondLevelCacheSessionStore;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.protocol.http.WebRequestCycleProcessor;
import org.apache.wicket.protocol.http.pagestore.DiskPageStore;
import org.apache.wicket.protocol.http.request.CryptedUrlWebRequestCodingStrategy;
import org.apache.wicket.protocol.http.request.WebRequestCodingStrategy;
import org.apache.wicket.request.IRequestCodingStrategy;
import org.apache.wicket.request.IRequestCycleProcessor;
import org.apache.wicket.request.target.coding.IndexedHybridUrlCodingStrategy;
import org.apache.wicket.session.ISessionStore;

import wickethub.data.DataHolder;
import wickethub.data.Indexer;
import wickethub.data.UpdateBatch;
import wickethub.data.Util;
import wickethub.domain.Resource;
import wickethub.repository.ResourceRepository;
import wickethub.web.page.EditResourcePage;
import wickethub.web.page.ListResourcePage;
import wickethub.web.page.ViewResourcePage;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Singleton;
import com.google.inject.matcher.Matchers;
import com.wideplay.warp.jpa.JpaPersistenceStrategy;
import com.wideplay.warp.jpa.JpaUnit;
import com.wideplay.warp.persist.PersistenceService;
import com.wideplay.warp.persist.PersistenceStrategy;
import com.wideplay.warp.persist.Transactional;
import com.wideplay.warp.persist.UnitOfWork;

public class WicketHubWebApplication extends WebApplication {

	private Injector injector;
	private final Timer timer = new Timer();
	
    @Override
    protected void init() {
    	
    	super.init();
    	
		// URL encoding strategies
		mountBookmarkablePage("/submit", EditResourcePage.class);
		mount(new IndexedHybridUrlCodingStrategy("/list", ListResourcePage.class));
		mount(new IndexedHybridUrlCodingStrategy("/resource", ViewResourcePage.class));
		
		getMarkupSettings().setDefaultMarkupEncoding("UTF-8");

		PersistenceStrategy jpa = JpaPersistenceStrategy.builder().properties(new Properties()).build();

		Module m = PersistenceService.using(jpa).across(UnitOfWork.REQUEST)
					.forAll(Matchers.any(), Matchers.annotatedWith(Transactional.class))
					.buildModule();
		
		injector = Guice.createInjector(m, new InjectionModule());
		
		addComponentInstantiationListener(new GuiceComponentInjector(this, injector));
		
		// load data into holder - how more elegant this would be in scala!
		
		DataHolder holder = injector.getInstance(DataHolder.class);
		ResourceRepository repo = injector.getInstance(ResourceRepository.class);
		
		for (Resource resource : repo.findAllRecentResources()) {
			if (resource.getTopics() != null)
				holder.addTopics(Util.getSetFromString(resource.getTopics()));
			if (resource.getVersions() != null)
				holder.addVersions(Util.getSetFromString(resource.getVersions()));
		}
		
		
		timer.scheduleAtFixedRate(new TimerTask() {
			@Override
			public void run() {
				UpdateBatch batch = injector.getInstance(UpdateBatch.class);
				batch.update();
			}
			
		}, 0, 60000);
		
	}
    
    @Override
	protected ISessionStore newSessionStore() {
		  return new SecondLevelCacheSessionStore(this, new DiskPageStore());
	}
    
	@Override
    public Session newSession(Request request, Response response) {
    	return new WicketHubWebSession(request);
    }    
	
	@Override
	protected IRequestCycleProcessor newRequestCycleProcessor() {
	    return new WebRequestCycleProcessor() {
	        protected IRequestCodingStrategy newRequestCodingStrategy() {
	            return new CryptedUrlWebRequestCodingStrategy(new WebRequestCodingStrategy());
	        }
	    };
	}
	
	@Override
	protected void onDestroy() {
		Indexer indexer = injector.getInstance(Indexer.class);
		indexer.closeIndexWriter();
		timer.cancel();
	}
	
	@Override
	public Class<? extends Page> getHomePage() {
		return ListResourcePage.class;
	}
	
}

class InjectionModule extends AbstractModule {
	
	protected void configure() {
		bindConstant().annotatedWith(JpaUnit.class).to("wickethub-pu");
		bind(ServiceInitializer.class).asEagerSingleton();
		bind(Indexer.class).asEagerSingleton();
	}
	
}

@Singleton
class ServiceInitializer { 

	@Inject
	ServiceInitializer(PersistenceService service) {
		// initialize warp-persist for JPA
		service.start();
		
	} 

}